#ifndef __VANILA_PARSE_PRECEDENCE_HH__
#define __VANILA_PARSE_PRECEDENCE_HH__

#include "vanila/token.h"
#include "utils/singleton.h"
#include <map>

namespace vanila
{
//! \brief parse precedence
enum Precedence
{
    NONE = 0,
    ASSIGNMENT,  // =
    OR,          // or
    AND,         // and
    EQUALITY,    // == !=
    COMPARISON,  // < > <= >=
    TERM,        // + -
    FACTOR,      // * /
    UNARY,       // ! -
    CALL,        // . ()
    INDEX,       // []
    PRIMARY,
};

class Compiler;

//! \brief Prefix parser interface
class PrefixParser
{
public:
    virtual void parse(Compiler* compiler, bool canAssign) const = 0;
};

//! \brief infix parser interface
class InfixParser
{
public:
    virtual void parse(Compiler* compiler, bool canAssign) const = 0;
};

//! \brief parse rule struct, each token has a rule!
struct ParseRule
{
    PrefixParser* prefix;
    InfixParser*  infix;
    Precedence    precedence;
};

//! \brief Parser class
class Parser : public utils::Singleton<Parser>
{
public:
    Parser();
    ~Parser() noexcept;

public:
    //! \brief parse the token which has more precedence
    void parsePrecedence(Compiler* compiler, Precedence precedence) const;

    //! \brief Get the Parse Rule object
    //! \param[in] tokenType specify token type
    ParseRule getParseRule(TokenType tokenType)
    { return this->_parseSelector[tokenType]; }

private:
    std::map<TokenType, ParseRule> _parseSelector;
};

#define REGISTER_PREFIX_PARSER(ClassName) \
class ClassName : public PrefixParser, public utils::Singleton<ClassName>\
{\
public:\
    virtual void parse(Compiler* compiler, bool canAssign) const override;\
};

#define REGISTER_INFIX_PARSER(ClassName) \
class ClassName : public InfixParser, public utils::Singleton<ClassName>\
{\
public:\
    virtual void parse(Compiler* compiler, bool canAssign) const override;\
};

REGISTER_PREFIX_PARSER(UnaryParser)
REGISTER_PREFIX_PARSER(GroupingParser)
REGISTER_PREFIX_PARSER(IntegerParser)
REGISTER_PREFIX_PARSER(DecimalParser)
REGISTER_PREFIX_PARSER(LiteralParser)
REGISTER_PREFIX_PARSER(StringParser)
REGISTER_PREFIX_PARSER(VariableParser)
REGISTER_PREFIX_PARSER(ThisParser)
REGISTER_PREFIX_PARSER(SuperParser)
REGISTER_PREFIX_PARSER(ListParser)
REGISTER_PREFIX_PARSER(DictParser)

REGISTER_INFIX_PARSER(AndParser)
REGISTER_INFIX_PARSER(OrParser)
REGISTER_INFIX_PARSER(BinaryParser)
REGISTER_INFIX_PARSER(CallParser)
REGISTER_INFIX_PARSER(DotParser)
REGISTER_INFIX_PARSER(IndexParser)

}

#endif